/*
* LWJGLBase.java
* Copyright (C) 2004
* 
* $Id: LWJGLBase.java,v 1.2 2004/12/20 21:51:18 cawe Exp $
*/
/*
Copyright (C) 1997-2001 Id Software, Inc.

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/
using System;
using Defines = Suake2.UI.Defines;
using VID = Suake2.UI.client.VID;
using viddef_t = Suake2.UI.client.viddef_t;
using cvar_t = Suake2.UI.game.cvar_t;
using xcommand_t = Suake2.UI.qcommon.xcommand_t;
using LWJGLException = org.lwjgl.LWJGLException;
using Display = org.lwjgl.opengl.Display;
using DisplayMode = org.lwjgl.opengl.DisplayMode;
using GLImpl = org.lwjgl.util.GLImpl;
namespace Suake2.UI.render.lwjgl
{
	
	/// <summary> LWJGLBase
	/// 
	/// </summary>
	/// <author>  dsanders/cwei
	/// </author>
	public abstract class LWJGLBase
	{
		virtual public java.awt.DisplayMode[] ModeList
		{
			get
			{
				DisplayMode[] modes = Display.getAvailableDisplayModes();
				
				//UPGRADE_TODO: Class 'java.util.LinkedList' was converted to 'System.Collections.ArrayList' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilLinkedList'"
				System.Collections.ArrayList l = new System.Collections.ArrayList();
				l.Add(toAwtDisplayMode(oldDisplayMode));
				
				for (int i = 0; i < modes.Length; i++)
				{
					DisplayMode m = modes[i];
					
					if (m.getBitsPerPixel() != oldDisplayMode.getBitsPerPixel())
						continue;
					if (m.getFrequency() > oldDisplayMode.getFrequency())
						continue;
					if (m.getHeight() < 240 || m.getWidth() < 320)
						continue;
					
					int j = 0;
					java.awt.DisplayMode ml = null;
					for (j = 0; j < l.Count; j++)
					{
						ml = (java.awt.DisplayMode) l[j];
						if (ml.getWidth() > m.getWidth())
							break;
						if (ml.getWidth() == m.getWidth() && ml.getHeight() >= m.getHeight())
							break;
					}
					if (j == l.Count)
					{
						l.Insert(l.Count, toAwtDisplayMode(m));
					}
					else if (ml.getWidth() > m.getWidth() || ml.getHeight() > m.getHeight())
					{
						l.Insert(j, toAwtDisplayMode(m));
					}
					else if (m.getFrequency() > ml.getRefreshRate())
					{
						l.RemoveAt(j);
						l.Insert(j, toAwtDisplayMode(m));
					}
				}
				java.awt.DisplayMode[] ma = new java.awt.DisplayMode[l.Count];
				l.toArray(ma);
				return ma;
			}
			
		}
		virtual public DisplayMode[] LWJGLModeList
		{
			get
			{
				DisplayMode[] modes = Display.getAvailableDisplayModes();
				
				//UPGRADE_TODO: Class 'java.util.LinkedList' was converted to 'System.Collections.ArrayList' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilLinkedList'"
				System.Collections.ArrayList l = new System.Collections.ArrayList();
				l.Add(oldDisplayMode);
				
				for (int i = 0; i < modes.Length; i++)
				{
					DisplayMode m = modes[i];
					
					if (m.getBitsPerPixel() != oldDisplayMode.getBitsPerPixel())
						continue;
					if (m.getFrequency() > oldDisplayMode.getFrequency())
						continue;
					if (m.getHeight() < 240 || m.getWidth() < 320)
						continue;
					
					int j = 0;
					DisplayMode ml = null;
					for (j = 0; j < l.Count; j++)
					{
						ml = (DisplayMode) l[j];
						if (ml.getWidth() > m.getWidth())
							break;
						if (ml.getWidth() == m.getWidth() && ml.getHeight() >= m.getHeight())
							break;
					}
					if (j == l.Count)
					{
						l.Insert(l.Count, m);
					}
					else if (ml.getWidth() > m.getWidth() || ml.getHeight() > m.getHeight())
					{
						l.Insert(j, m);
					}
					else if (m.getFrequency() > ml.getFrequency())
					{
						l.RemoveAt(j);
						l.Insert(j, m);
					}
				}
				DisplayMode[] ma = new DisplayMode[l.Count];
				SupportClass.ICollectionSupport.ToArray(l, ma);
				return ma;
			}
			
		}
		// IMPORTED FUNCTIONS
		protected internal DisplayMode oldDisplayMode;
		
		protected internal GLImpl gl = new GLImpl();
		
		// window position on the screen
		internal int window_xpos, window_ypos;
		protected internal viddef_t vid = new viddef_t();
		
		// handles the post initialization with LWJGLRenderer
		protected internal abstract bool R_Init2();
		
		protected internal cvar_t vid_fullscreen;
		
		// enum rserr_t
		protected internal const int rserr_ok = 0;
		protected internal const int rserr_invalid_fullscreen = 1;
		protected internal const int rserr_invalid_mode = 2;
		protected internal const int rserr_unknown = 3;
		
		private java.awt.DisplayMode toAwtDisplayMode(DisplayMode m)
		{
			return new java.awt.DisplayMode(m.getWidth(), m.getHeight(), m.getBitsPerPixel(), m.getFrequency());
		}
		
		//UPGRADE_NOTE: ref keyword was added to struct-type parameters. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1303'"
		private DisplayMode findDisplayMode(ref System.Drawing.Size dim)
		{
			DisplayMode mode = null;
			DisplayMode m = null;
			DisplayMode[] modes = LWJGLModeList;
			int w = dim.Width;
			int h = dim.Height;
			
			for (int i = 0; i < modes.Length; i++)
			{
				m = modes[i];
				if (m.getWidth() == w && m.getHeight() == h)
				{
					mode = m;
					break;
				}
			}
			if (mode == null)
				mode = oldDisplayMode;
			return mode;
		}
		
		internal virtual System.String getModeString(DisplayMode m)
		{
			System.Text.StringBuilder sb = new System.Text.StringBuilder();
			sb.Append(m.getWidth());
			sb.Append('x');
			sb.Append(m.getHeight());
			sb.Append('x');
			sb.Append(m.getBitsPerPixel());
			sb.Append('@');
			sb.Append(m.getFrequency());
			sb.Append("Hz");
			return sb.ToString();
		}
		
		/// <param name="dim">
		/// </param>
		/// <param name="mode">
		/// </param>
		/// <param name="fullscreen">
		/// </param>
		/// <returns> enum rserr_t
		/// </returns>
		//UPGRADE_NOTE: ref keyword was added to struct-type parameters. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1303'"
		protected internal virtual int GLimp_SetMode(ref System.Drawing.Size dim, int mode, bool fullscreen)
		{
			
			System.Drawing.Size newDim = new System.Drawing.Size(0, 0);
			
			VID.Printf(Defines.PRINT_ALL, "Initializing OpenGL display\n");
			
			VID.Printf(Defines.PRINT_ALL, "...setting mode " + mode + ":");
			
			/*
			* fullscreen handling
			*/
			if (oldDisplayMode == null)
			{
				oldDisplayMode = Display.getDisplayMode();
			}
			
			//UPGRADE_NOTE: ref keyword was added to struct-type parameters. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1303'"
			if (!VID.GetModeInfo(ref newDim, mode))
			{
				VID.Printf(Defines.PRINT_ALL, " invalid mode\n");
				return rserr_invalid_mode;
			}
			
			VID.Printf(Defines.PRINT_ALL, " " + newDim.Width + " " + newDim.Height + '\n');
			
			// destroy the existing window
			GLimp_Shutdown();
			
			Display.setTitle("Jake2");
			
			//UPGRADE_NOTE: ref keyword was added to struct-type parameters. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1303'"
			DisplayMode displayMode = findDisplayMode(ref newDim);
			newDim.Width = displayMode.getWidth();
			newDim.Height = displayMode.getHeight();
			
			if (fullscreen)
			{
				try
				{
					Display.setDisplayMode(displayMode);
				}
				catch (LWJGLException e)
				{
					return rserr_invalid_mode;
				}
				
				Display.setLocation(0, 0);
				
				try
				{
					Display.setFullscreen(fullscreen);
				}
				catch (LWJGLException e)
				{
					return rserr_invalid_fullscreen;
				}
				
				VID.Printf(Defines.PRINT_ALL, "...setting fullscreen " + getModeString(displayMode) + '\n');
			}
			else
			{
				try
				{
					Display.setDisplayMode(displayMode);
				}
				catch (LWJGLException e)
				{
					return rserr_invalid_mode;
				}
				
				try
				{
					Display.setFullscreen(false);
				}
				catch (LWJGLException e)
				{
					return rserr_invalid_fullscreen;
				}
				Display.setLocation(window_xpos, window_ypos);
			}
			
			vid.width = newDim.Width;
			vid.height = newDim.Height;
			
			try
			{
				Display.create();
			}
			catch (LWJGLException e)
			{
				return rserr_unknown;
			}
			
			// let the sound and input subsystems know about the new window
			VID.NewWindow(vid.width, vid.height);
			return rserr_ok;
		}
		
		protected internal virtual void  GLimp_Shutdown()
		{
			if (oldDisplayMode != null && Display.isFullscreen())
			{
				try
				{
					Display.setDisplayMode(oldDisplayMode);
				}
				catch (System.Exception e)
				{
					SupportClass.WriteStackTrace(e, Console.Error);
				}
			}
			
			while (Display.isCreated())
			{
				Display.destroy();
			}
		}
		
		/// <returns> true
		/// </returns>
		protected internal virtual bool GLimp_Init(int xpos, int ypos)
		{
			// do nothing
			window_xpos = xpos;
			window_ypos = ypos;
			return true;
		}
		
		protected internal virtual void  GLimp_EndFrame()
		{
			gl.glFlush();
			// swap buffers
			Display.update();
		}
		
		protected internal virtual void  GLimp_BeginFrame(float camera_separation)
		{
			// do nothing
		}
		
		protected internal virtual void  GLimp_AppActivate(bool activate)
		{
			// do nothing
		}
		
		protected internal virtual void  GLimp_EnableLogging(bool enable)
		{
			// do nothing
		}
		
		protected internal virtual void  GLimp_LogNewFrame()
		{
			// do nothing
		}
		
		/// <summary> this is a hack for jogl renderers.</summary>
		/// <param name="callback">
		/// </param>
		public void  updateScreen(xcommand_t callback)
		{
			callback.execute();
		}
	}
}